package com.jl;

import lombok.SneakyThrows;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * bean工具
 */
public class JLBean {

    /**
     * 对象拷贝
     *
     * @param resultClass 返回对象class
     * @param dataEntity  数据对象
     * @param <T>
     * @return
     */
    @SneakyThrows
    public static <T> T copy(Class<T> resultClass, Object dataEntity) {
        return copy(resultClass.newInstance(), dataEntity);
    }

    /**
     * 对象拷贝
     *
     * @param resultEntity 返回对象
     * @param dataEntity   数据对象
     * @param <T>
     * @return
     */
    public static <T> T copy(T resultEntity, Object dataEntity) {
        List<JLTuple.Tuple3<String, Object, Class<?>>> resultProperty = JLReflect.PropertyReflect.getProperty(resultEntity);
        Map<String, JLTuple.Tuple3<String, Object, Class<?>>> resultPropertyMap = resultProperty.stream().collect(Collectors.toMap(o -> o.getV1(), Function.identity(), (key1, key2) -> key2));
        List<JLTuple.Tuple3<String, Object, Class<?>>> dataProperty = JLReflect.PropertyReflect.getProperty(dataEntity);
        Map<String, JLTuple.Tuple3<String, Object, Class<?>>> dataPropertyMap = dataProperty.stream().collect(Collectors.toMap(o -> o.getV1(), Function.identity(), (key1, key2) -> key2));
        resultPropertyMap.forEach((resultName, tuple3) -> {
            JLTuple.Tuple3<String, Object, Class<?>> dataTuple3 = dataPropertyMap.get(resultName);
            if (dataTuple3 == null || dataTuple3.getV2() == null) {
                return;
            }
            Object value = dataTuple3.getV2();
            char[] cs = dataTuple3.getV1().toCharArray();
            cs[0] -= 32;
            Method method = JLReflect.MethodReflect.getMethod(resultEntity.getClass(), "set" + String.valueOf(cs), tuple3.getV3());
            Object[] param = dataTuple3.getV3().equals(tuple3.getV3()) ? new Object[]{value} : JLReflect.MethodReflect.checkParamType(method.getParameters(), new Object[]{value});
            try {
                method.invoke(resultEntity, param);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        return resultEntity;
    }

    /**
     * 集合拷贝
     *
     * @param resultClass 返回集合泛型class
     * @param dataList    数据集合
     * @param <T>         泛型
     * @return
     */
    public static <T> List<T> copy(Class<T> resultClass, List<?> dataList) {
        List<T> result = new ArrayList<>(dataList.size());
        for (Object o : dataList) {
            result.add(copy(resultClass, o));
        }
        return result;
    }

    /**
     * 递归生成树
     *
     * @param father      最顶层父级
     * @param entities    全部数据集合
     * @param fatherCode  父级关联子级属性名
     * @param sonCode     子级关联父级属性名
     * @param sonListCode 存放子级集合属性名
     * @param <T>
     * @return
     */
    public static <T> List<T> tree(T father, List<T> entities, JLLambda.JLFunction<T, ?> fatherCode, JLLambda.JLFunction<T, ?> sonCode, JLLambda.JLFunction<T, ?> sonListCode) {
        List<T> tree = new ArrayList<>();
        //父属性值
        String fatherProperty = JLLambda.getProperty(fatherCode);
        Object fatherValue = JLReflect.PropertyReflect.getProperty(father, fatherProperty).getV2();
        //子属性名称
        String sonProperty = JLLambda.getProperty(sonCode);
        //子集合set方法名
        String sonListProperty = String.format("s%s", JLLambda.getMethod(sonListCode).substring(1));
        for (T entity : entities) {
            //子属性值
            Object sonValue = JLReflect.PropertyReflect.getProperty(entity, sonProperty).getV2();
            if (sonValue != null && sonValue.toString().equals(fatherValue.toString())) {
                tree.add(entity);
                JLReflect.MethodReflect.getMethodValue(entity, sonListProperty, tree(entity, entities, fatherCode, sonCode, sonListCode));
            }
        }
        return tree;
    }

}
